// HSR.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "HSR.h"

#include "DIBAPI.H"

#include "Database.h"
#include "BorderTracing.h"

#include <assert.h>

#include <list>
using namespace std;

#include <math.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// The one and only application object

CWinApp theApp;

static const double PI = 4.0 * atan(1.0);

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int nRetCode = 0;

	// initialize MFC and print and error on failure
	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
	{
		// TODO: change error code to suit your needs
		_tprintf(_T("Fatal Error: MFC initialization failed\n"));
		nRetCode = 1;
	}
	else
	{
		// TODO: code your application's behavior here.		
		Database db;


#define SWITCH_TELL "/t"
#define SWITCH_ASK "/a"
#define DATABASE_FILE_NAME _T("..\\hsr_db")

		CFile databaseFile;
		CFileStatus databaseFileStatus;

		if ( CFile::GetStatus(DATABASE_FILE_NAME, databaseFileStatus) )
		{
			databaseFile.Open(DATABASE_FILE_NAME, CFile::modeReadWrite);

			CArchive readArchive(&databaseFile, CArchive::load);
			db.Serialize(readArchive);
			readArchive.Close();

			// go to begin
			databaseFile.SeekToBegin();
		}
		else
		{
			CFileException fileException;
			
			databaseFile.Open( DATABASE_FILE_NAME, CFile::modeCreate | CFile::modeReadWrite, &fileException );
		}

		database_list& db_list = db.GetList();

		bool tell = true;
		TCHAR* srcFileName = _T("..\\..\\templates\\t98zoom.bmp");
		TCHAR* fileCategory = _T("human");

		TCHAR* dstFileName = _T("..\\output.bmp");

		CFile srcFile, dstFile;

		dstFile.Open(dstFileName, CFile::modeWrite | CFile::modeCreate);

		if (srcFile.Open(srcFileName, CFile::modeRead))
		{
			HDIB dib = ReadDIBFile(srcFile);
			HDIB dstDib = (HDIB)::CopyHandle((HGLOBAL)dib);

			BYTE* lpS = (BYTE*)::GlobalLock((HGLOBAL)dib);
			BYTE* lpD = (BYTE*)::GlobalLock((HGLOBAL)dstDib);

			BYTE* lpSrc = (BYTE*)::FindDIBBits((LPSTR)lpS);
			BYTE* lpDst = (BYTE*)::FindDIBBits((LPSTR)lpD);

			DWORD dwWidth  = ::DIBWidth((LPSTR)lpS);
			DWORD dwHeight = ::DIBHeight((LPSTR)lpS);
			DWORD w=WIDTHBYTES(dwWidth*8);

			memset(lpDst, WHITE, w * dwHeight);

			list<ChainCode> l;

			ChainCode::Extract(dwHeight, dwWidth, w, lpSrc, l);
			assert(l.size() == 1);
			ChainCode c = l.front();



			int n = c.chain.size();
			{
			pair<double, double> dft[759];

			
			for (int u = 0; u < sizeof(dft)/sizeof(dft[0]); u++)
			{ 
			
			Point p = c.p;

			int k = 0;

			double fi = 2 * PI * u * k / n;
			dft[u].first  =   p.x * cos(fi) + p.y * sin(fi);
			dft[u].second = - p.x * sin(fi) + p.y * cos(fi);
			
			// draw first point
			//lpDst[p.y * w + p.x] = c.c;

			for(list<unsigned char>::iterator itc = c.chain.begin(); itc != c.chain.end(); itc++)
			{

				p.x = ChainCode::GetX(p.x, *itc);
				p.y = ChainCode::GetY(p.y, *itc);

				fi = 2 * PI * u * k / n;
				dft[u].first  +=   p.x * cos(fi) + p.y * sin(fi);
				dft[u].second += - p.x * sin(fi) + p.y * cos(fi);

				//lpDst[p.y * w + p.x] = c.c;

				k++;
			}

			dft[u].first  /= n;
			dft[u].second /= n;

			}

			for (int k = 0; k < n; k++)
			{
			pair<double, double> p0;

			p0.first  = 0.0;
			p0.second = 0.0;

			for (int u = 0; u < sizeof(dft)/sizeof(dft[0]); u++)
			{
				double fi = -2 * PI  * u * k / n;
				p0.first  +=  dft[u].first * cos(fi) + dft[u].second * sin(fi);
				p0.second += -dft[u].first * sin(fi) + dft[u].second * cos(fi);


			}

			//p0.first  /= n;
			//p0.second /= n;

			lpDst[(int)(p0.second + 0.5) * w + (int)(p0.first + 0.5)] = c.c;

			}

			}

			SaveDIB(dstDib, dstFile); 

			srcFile.Close();

			::GlobalUnlock((HGLOBAL)dib);
			::GlobalUnlock((HGLOBAL)dstDib);
		}

		dstFile.Close();

		CArchive writeArchive(&databaseFile, CArchive::store);
		db.Serialize(writeArchive);
		writeArchive.Close();

	}

	return nRetCode;
}
